
#if 1

const char *template_version = "v2.0";
const char *template_date = "20240808";

/*
 * tail/head/tailport/headport
 */
const char *MODE = "tailport";

int NODE_COLOR_MIN = 180;
int NODE_COLOR_MAX = 230;

int EDGE_COLOR_MIN = 10;
int EDGE_COLOR_MAX = 150;

int CLUSTER_COLOR_MIN = 230;
int CLUSTER_COLOR_MAX = 250;

// gvtext: [o/r/or] Origin or/and Render, generate gv file
const char *gvtext = "or";
// for strict of pygraphviz.AGraph
const char *graph_strict = "false";

// typedef int gvfunc_t;

#endif

#ifndef LABEL_NODE
#define LABEL_NODE(_node, _label, ...) \
    _node [label=_label, ##__VA_ARGS__]
#endif

#ifndef CLUSTER_START
#define CLUSTER_START(_name) \
    subgraph cluster_##_name
#endif

#ifndef KEEP_LABEL_NODE
#define KEEP_LABEL_NODE(_node, _label, ...) \
    KEEP(LABEL_NODE(_node, _label, ##__VA_ARGS__))
#endif

#ifndef KEEP_CLUSTER_START
#define KEEP_CLUSTER_START(_name, ...) \
    KEEP(CLUSTER_START(_name, ##__VA_ARGS__))
#endif

/* http://www.graphviz.org/doc/info/attrs.html */

/*
 * splines:
 * none
 * line/false
 * polyline
 * curved
 * ortho
 * spline/true
 */
KEEP(   // graphviz text
    graph [rankdir=LR];
    splines = "polyline";
    node [shape=box, width=2];
    edge [minlen=2, penwidth=1];
);

struct demo {
    int a;
    int b;
    int c;
};


struct demo1 {
    int a;

    union {
        struct
        {
            unsigned long flags;
            union
            {
                struct list_head lru;
                struct
                {
                    void *__filler;
                    unsigned int mlock_count;
                };
            };
            struct address_space *mapping;
            pgoff_t index;
            void *private;
            atomic_t _mapcount;
            atomic_t _refcount;
        };
        struct page page;
    } uvars;
    unsigned long _flags_1;
    unsigned long __head;
    unsigned char _folio_dtor;
    unsigned char _folio_order;
    atomic_t _total_mapcount;
    atomic_t _pincount;

    int (*func)(void);

    char buf[111];

    ...;
};

typedef struct demo demo_t;
typedef struct {} empty_t;

invis_struct invis_st {
	a;
	b;
	c;
};

/*
|          | solid | dashed | dotted | bold | tapered | invis |
|----------|-------|--------|--------|------|---------|-------|
|  none    |   -   |   --   |  ---   | ---- |  -----  |   ~   |
|  both    |   +   |   ++   |  +++   | ++++ |  +++++  |       |
|  forward |   >   |   >>   |  >>>   | >>>> |  >>>>>  |       |
|  back    |   <   |   <<   |  <<<   | <<<< |  <<<<<  |       |
*/

CTREE(
+-- root
|   +-- node0
|   |   +-- node00
|   |   +-- node01
|   +-- node1
|   |   +-- node10
|   |   +-- node11
);

void main()
{
    struct demo var1, var2;
    struct demo array[];

    // x
	invis_struct invis_st invis_test;

    var1.c + var2.b;
    var1.a --- var2.a;

    func();

    funcA >>>>> funcB;

    KEEP(abcd [shape=ellipse]);

CTREE(
xnode00  --+   |   |
xnode01  --+   |   |
      xnode0 --+   |
xnode10  --+   |   |
xnode11  --+   |   |
      xnode1 --+   |
           xroot --+
);

}

void func()
{
    struct demo varA;
    struct demo1 varB;

    KEEP(a -> b [label="keep a -> b"]);
    array.a <<< varB.uvars.private;
}
